package cn.stylefeng.guns.modular.business.service.impl;


import cn.stylefeng.guns.base.pojo.node.TreeviewNode;
import cn.stylefeng.guns.base.pojo.node.ZTreeNode;
import cn.stylefeng.guns.base.pojo.page.LayuiPageFactory;
import cn.stylefeng.guns.config.redis.RedisHandler;
import cn.stylefeng.guns.modular.business.common.Constants;
import cn.stylefeng.guns.modular.business.entity.Category;
import cn.stylefeng.guns.modular.business.mapper.CategoryMapper;
import cn.stylefeng.guns.modular.business.model.result.CategoryResultView;
import cn.stylefeng.guns.modular.business.model.result.CategoryTypeView;
import cn.stylefeng.guns.modular.business.service.CategoryService;
import cn.stylefeng.guns.sys.core.exception.enums.BizExceptionEnum;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

@Service
@Slf4j
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    @Resource
    private CategoryMapper categoryMapper;
    @Autowired
    RedisHandler redisHandler;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addCategory(Category category) {
        if (ToolUtil.isOneEmpty(category, category.getName(), category.getPid())) {
            throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
        }
        this.categorySetPidsAndLevel(category);
        if (category.getPid() != 0) {
            List<CategoryTypeView> categoriesType = getCategoriesType();
            categoriesType.forEach(categoryTypeView -> {
                if (category.getPids().contains("[" + categoryTypeView.getCategoryId() + "]")) {
                    category.setCategoryType(categoryTypeView.getCategoryType());
                }
            });
        }
        this.save(category);
        cacheCategory(category);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editCategory(Category category) {
        Category category1 = categoryMapper.selectById(category.getCategoryId());
        if (ToolUtil.isOneEmpty(category, category.getCategoryId(), category.getName())) {
            throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
        }
        this.updateById(category);
        cacheCategory(category1);
    }


    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void deleteCategory(Long categoryId) {
        Category category = categoryMapper.selectById(categoryId);
        QueryWrapper<Category> wrapper = new QueryWrapper<>();
        wrapper = wrapper.like("PIDS", "%[" + category.getCategoryId() + "]%");
        List<Category> subDepts = categoryMapper.selectList(wrapper);
        for (Category temp : subDepts) {
            this.removeById(temp.getCategoryId());
        }
        this.removeById(category.getCategoryId());
        cacheCategory(category);
    }

    @Override
    public List<ZTreeNode> tree() {
        return this.baseMapper.tree();
    }

    @Override
    public List<TreeviewNode> treeviewNodes() {
        return this.baseMapper.treeviewNodes();
    }


    @Override
    public Page<Category> list(String condition, String categoryId) {
        Page page = LayuiPageFactory.defaultPage();
        page.setRecords(baseMapper.list(page, condition, categoryId));
        return page;
    }

    private void categorySetPidsAndLevel(Category category) {
        if (ToolUtil.isEmpty(category.getPid()) || category.getPid().equals(0L)) {
            category.setPid(0L);
            category.setPids("[0],");
            category.setLevel(1L);
        } else {
            Long pid = category.getPid();
            Category temp = this.getById(pid);
            String pids = temp.getPids();
            category.setPid(pid);
            category.setPids(pids + "[" + pid + "],");
            category.setLevel((long) Arrays.asList(category.getPids().split(",")).size());
        }
    }

    private void cacheCategory(Category category) {
        Long pid = category.getPid();
        List<Category> categories = categoryMapper.selectList(new QueryWrapper<Category>()
                .eq("PID", pid).orderByAsc("SORT"));
        HashMap<String, String> hashMap = new HashMap<>();
        redisHandler.getGlobalRedisTemplate().remove(Constants.CATEGORY_KEY, ":" + pid);
        if (CollectionUtils.isNotEmpty(categories)) {
            hashMap.put(pid.toString(), JSONObject.toJSONString(categories));
            redisHandler.getGlobalRedisTemplate().cacheHashAll(Constants.CATEGORY_KEY, ":" + pid, hashMap);
        }
    }

    @Override
    public void initCacheCategories() {
        List<Category> categories = categoryMapper.selectList(new QueryWrapper<Category>()
                .eq("PID", 0).orderByAsc("SORT"));
        if (!CollectionUtils.isEmpty(categories)) {
            HashMap<String, String> hashMap = new HashMap<>();
            hashMap.put("0", JSONObject.toJSONString(categories));
            redisHandler.getGlobalRedisTemplate().cacheHashAll(Constants.CATEGORY_KEY, ":" + "0", hashMap);
            cacheCategoriesToRedis(categories);
        }

    }

    @Override
    public Category getCategoryById(Long categoryId) {
        return categoryMapper.selectById(categoryId);
    }

    private void cacheCategoriesToRedis(List<Category> categories) {
        categories.forEach(category -> {
            List<Category> categoryList = categoryMapper.selectList(new QueryWrapper<Category>()
                    .eq("PID", category.getCategoryId()).orderByAsc("SORT"));
            if (CollectionUtils.isNotEmpty(categoryList)) {
                HashMap<String, String> hashMap = new HashMap<>();
                hashMap.put(category.getCategoryId().toString(), JSONObject.toJSONString(categoryList));
                redisHandler.getGlobalRedisTemplate().cacheHashAll(Constants.CATEGORY_KEY, ":" + category.getCategoryId(), hashMap);
                cacheCategoriesToRedis(categoryList);
            }
        });
    }


    @Override
    public List<CategoryResultView> getCategories(Long categoryId, Boolean isAll) {
        List<CategoryResultView> categoryResultViews = new ArrayList<>();
        String categoryJson = redisHandler.getGlobalRedisTemplate().getHash(Constants.CATEGORY_KEY, ":" + categoryId, categoryId.toString());
        if (categoryJson != null) {
            List<Category> categories = JSONObject.parseArray(categoryJson, Category.class);
            categories.forEach(category -> {
                CategoryResultView categoryResultView = new CategoryResultView();
                categoryResultView.setCategoryId(category.getCategoryId());
                categoryResultView.setName(category.getName());
                categoryResultView.setPicture(category.getPicture());
                categoryResultView.setCategoryType(category.getCategoryType());
                if (isAll) {
                    String s = redisHandler.getGlobalRedisTemplate().getHash(Constants.CATEGORY_KEY, ":" + category.getCategoryId().toString(), category.getCategoryId().toString());
                    if (s != null) {
                        List<Category> categoryList = JSONObject.parseArray(s, Category.class);
                        categoryResultView.setCategories(categoryList);
                    }
                }
                categoryResultViews.add(categoryResultView);
            });
        }
        return categoryResultViews;
    }

    @Override
    public List<CategoryTypeView> getCategoriesType() {
        List<CategoryTypeView> categoryTypeViews = new ArrayList<>();
        List<Category> categories = categoryMapper.selectList(new QueryWrapper<Category>()
                .eq("PID", 0).isNotNull("CATEGORY_TYPE"));

        categories.forEach(category -> {
            CategoryTypeView categoryTypeView = new CategoryTypeView();
            categoryTypeView.setCategoryId(category.getCategoryId());
            categoryTypeView.setCategoryType(category.getCategoryType());
            categoryTypeViews.add(categoryTypeView);
        });
        return categoryTypeViews;
    }
}
